/*
 * DFA
 * 
 * Version 
 *
 * 23/10/2013
 * 
 * Licencia
 */
package proyecto2.logica;

import java.util.ArrayList;
import java.util.LinkedList;

public class DFA extends NFA {

    public DFA() {
        this.alfabeto = null;
        this.estados = null;
        this.finales = null;
        this.inicial = null;
        this.transiciones = null;
    }

    /**
     *
     * @param estados
     * @param alfabeto
     * @param transiciones
     * @param inicial
     * @param finales
     */
    public DFA(ArrayList<Estado> estados, ArrayList<String> alfabeto, ArrayList<Transicion> transiciones, Estado inicial, ArrayList<Estado> finales) {
        this.alfabeto = alfabeto;
        this.estados = estados;
        this.finales = finales;
        this.inicial = inicial;
        this.transiciones = transiciones;

    }

    public Gramatica toGrammar() {
        return new Gramatica(this);
    }

    public NFA toNFA() {
        return null;

    }

    public DFA armaAutomata(DFA dfa, int op) {
        DFA miDFA = null;
        ArrayList<Estado> Q = new ArrayList<>();
        ArrayList<Transicion> delta = new ArrayList<>();
        ArrayList<Estado> F = new ArrayList<>();

        Estado es0 = this.getInicial();
        Estado es1 = dfa.getInicial();
        Estado ini = new Estado(concatenaE(this.getInicial(), dfa.getInicial()), false, true);
        Q.add(ini);
        LinkedList<Estado> queue = new LinkedList<>();
        backcraping(dfa, es0, es1, Q, delta, F, queue, op);
        F = sacaFinales(Q, dfa.getFinales(), op);
        miDFA = new DFA(Q, this.alfabeto, delta, ini, F);
        System.out.println(miDFA.getTransiciones());
        return miDFA;
    }

    public void backcraping(DFA dfa, Estado es0, Estado es1, ArrayList<Estado> Q, ArrayList<Transicion> delta, ArrayList<Estado> F, LinkedList<Estado> queue, int op) {
        Estado dequeue = null;
        Estado destino = null;
        Estado aux;
        Estado origen = null;
        ArrayList<Estado> h0 = null;
        ArrayList<Estado> h1 = null;
        for (int i = 0; i < this.getAlfabeto().size(); i++) {
            h0 = this.getEstadosTransicion(es0, this.getAlfabeto().get(i));
            h1 = dfa.getEstadosTransicion(es1, this.getAlfabeto().get(i));

            aux = new Estado(concatenaE(h0.get(0), h1.get(0)), false, false);
            if (yaEsta(Q, aux)) {
                destino = sacaXstring(Q, aux.getId());
            } else {
                destino = aux;
            }

            origen = sacaXstring(Q, concatenaE(es0, es1));
            if (!yaEsta(Q, destino)) {
                Q.add(destino);
                delta.add(new Transicion(origen, this.getAlfabeto().get(i), destino));
                queue.add(destino);
            } else {
                delta.add(new Transicion(origen, this.getAlfabeto().get(i), destino));
            }
        }
        dequeue = queue.pollFirst();
        if (dequeue != null) {
            String[] state = dequeue.getId().split("-");
            backcraping(dfa, sacaXstring(this, state[0]), sacaXstring(dfa, state[1]), Q, delta, F, queue, op);
        }
    }

    private String concatenaE(Estado s0, Estado s1) {
        return s0.getId() + "-" + s1.getId();
    }

    public boolean yaEsta(ArrayList<Estado> q, Estado e) {
        for (int i = 0; i < q.size(); i++) {
            if (q.get(i).getId().equals(e.getId())) {
                return true;
            }
        }
        return false;
    }

    public Estado sacaXstring(DFA dfa, String id) {
        ArrayList<Estado> lista = dfa.getEstados();
        for (int i = 0; i < lista.size(); i++) {
            if (id.equals(lista.get(i).getId())) {
                return lista.get(i);
            }
        }
        return null;
    }

    public Estado sacaXstring(ArrayList<Estado> Q, String id) {
        for (int i = 0; i < Q.size(); i++) {
            if (id.equals(Q.get(i).getId())) {
                return Q.get(i);
            }
        }
        return null;
    }

    public ArrayList<Estado> sacaFinales(ArrayList<Estado> Q, ArrayList<Estado> F, int op) {
        int tam = this.finales.size();
        ArrayList<Estado> Fn = new ArrayList<>();
        for (int i = 0; i < Q.size(); i++) {
            for (int j = 0; j < tam; j++) {
                for (int k = 0; k < F.size(); k++) {
                    if (!yaEsta(Fn, Q.get(i))) {
                        if (esFinal(Q.get(i), finales.get(j), F.get(k), op)) {
                            if (op == 3) {
                                if (esFinalDiferencia(Q.get(i), F)) {
                                    Q.get(i).setES_FINAL(true);
                                    Fn.add(Q.get(i));
                                } 
                             
                            } else { 
                                if(op == 2)
                                {
                                     if (esFinDiferencia(Q.get(i), F)) {
                                    Q.get(i).setES_FINAL(true);
                                    Fn.add(Q.get(i));
                                } 
                                }
                                else{
                                Q.get(i).setES_FINAL(true);
                                Fn.add(Q.get(i));}
                            }
                        }
                    }
                }
            }
        }
        return Fn;
    }

    public boolean esFinalDiferencia(Estado a, ArrayList<Estado> finalesRecibidos) {
        String[] state = a.getId().split("-");
        if (yaEsta(this.getFinales(), new Estado(state[0], true, true)) && yaEsta(finalesRecibidos, new Estado(state[1], true, true))) {
            return false;
        }
        return true;
    }  
    
        public boolean esFinDiferencia(Estado a, ArrayList<Estado> finalesRecibidos) {
        String[] state = a.getId().split("-");
        if (yaEsta(this.getFinales(), new Estado(state[0], true, true)) && yaEsta(finalesRecibidos, new Estado(state[1], true, true))
        || !yaEsta(this.getFinales(), new Estado(state[0], true, true)) && yaEsta(finalesRecibidos, new Estado(state[1], true, true) )) 
            return false;
        return true;
    }

    public boolean DFSB(Estado q, Estado f, Estado f0) {
        String[] state = q.getId().split("-");
        return (f.getId() == state[0] && f0.getId() == state[1]
                || f.getId() == state[1] && f0.getId() == state[0]);
    }

    public boolean esFinal(Estado comb, Estado es0, Estado es1, int op) {
        boolean b = false;
        switch (op) {
            case UNION:
                b = estaUnion(comb, es0.getId(), es1.getId());
                break;
            case INTERSECT:
                b = estaInters(comb, es0.getId(), es1.getId());
                break;
            case MINUS:
                b = estaDif(comb, es0.getId(), es1.getId());
                break;
            case SYMMETRIC_DIFFERENCE:
                b = estaDifSimetrica(comb, es0.getId(), es1.getId());
                break;
        }
        return b;
    }

    public boolean estaUnion(Estado e, String s0, String s1) {
        String[] state = e.getId().split("-");
        return (state[0].equals(s0) || state[1].equals(s1));
    }

    public boolean estaInters(Estado e, String s0, String s1) {
        String[] state = e.getId().split("-");
        return (state[0].equals(s0) && state[1].equals(s1));
    }

    public boolean estaDif(Estado e, String s0, String s1) {
        String[] state = e.getId().split("-");
        return (state[0].equals(s0) && !state[1].equals(s1));
    }

    public boolean estaDifSimetrica(Estado e, String s0, String s1) {
        String[] state = e.getId().split("-");
        return (state[0].equals(s0) && !state[1].equals(s1) || !state[0].equals(s0) && state[1].equals(s1));
    }
    final static int UNION = 0;
    final static int INTERSECT = 1;
    final static int MINUS = 2;
    final static int SYMMETRIC_DIFFERENCE = 3;
    
    
}
